package rx.genarator;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class SequenceAlter {
	
	public String javaSourcePath="d:\\workspace\\hmsms\\JavaSource";
	public String webContentPath="d:\\workspace\\hmsms\\WebContent";
	public String springDatabaseConfigueFilePath=this.webContentPath+"\\WEB-INF\\databaseContext.xml";
//	public String springDatabaseConfigueFilePath=this.javaSourcePath+"\\databaseContext.xml";
	public String voPath=this.javaSourcePath+"\\com\\poweroa\\haima\\hibernate\\changed";
	private Map stringNameSpaceMap = new HashMap(1);
	

	public static void main(String[] args) throws DocumentException, IOException{
		
		SequenceAlter sa=new SequenceAlter();
		sa.process();
		
	}
	
	
	
	public SequenceAlter() {
		super();
		this.stringNameSpaceMap.put("spring", "http://www.springframework.org/schema/beans");
	}



	public void process() throws DocumentException, IOException{
		File[] mappingFiles = new File(voPath).listFiles(new FilenameFilter(){
			
			public boolean accept(File dir, String name) {
				if(name.endsWith(".xml"))
					return true;
				else
					return false;
			}
			
		});
		List mappings=new ArrayList();
		Document dataContext= this.readNoDTDXML(new FileInputStream(springDatabaseConfigueFilePath));
		for (int i = 0; i < mappingFiles.length; i++) {
			Document doc=this.readHibernateXML(mappingFiles[i]);
			mappings.add(doc);
		}
		this.doProcess(dataContext, mappings);
	}
	
	public void doProcess(Document dataContext ,List mappings){
		Connection conn=null;
		try {
			XPath xpath=dataContext.createXPath("//spring:bean[@id='dataSource']");
			xpath.setNamespaceURIs(this.stringNameSpaceMap);
//			Node dataSourceBean = dataContext.selectSingleNode("//bean[@id='dataSource']");
			Node dataSourceBean = xpath.selectSingleNode(dataContext);
			XPath xpath2=dataContext.createXPath("/spring:beans/spring:bean/spring:property[@name='driverClassName']/spring:value");
			xpath2.setNamespaceURIs(this.stringNameSpaceMap);
			String driverClassName=xpath2.selectSingleNode(dataContext).getText();
			Class.forName(driverClassName);
			
			XPath xpath3=dataContext.createXPath("/spring:beans/spring:bean/spring:property[@name='username']/spring:value");
			xpath3.setNamespaceURIs(this.stringNameSpaceMap);
			String username=xpath3.selectSingleNode(dataContext).getText();
			XPath xpath4=dataContext.createXPath("/spring:beans/spring:bean/spring:property[@name='password']/spring:value");
			xpath4.setNamespaceURIs(this.stringNameSpaceMap);
			String password=xpath4.selectSingleNode(dataContext).getText();
			XPath xpath5=dataContext.createXPath("/spring:beans/spring:bean/spring:property[@name='url']/spring:value");
			xpath5.setNamespaceURIs(this.stringNameSpaceMap);
			String url=xpath5.selectSingleNode(dataContext).getText();
			conn = DriverManager.getConnection(url, username, password);
			System.out.println(url);
			System.out.println(username);
			System.out.println(password);
			for (Iterator iter = mappings.iterator(); iter.hasNext();) {
				Document mapping = (Document) iter.next();
				try {
					this.doInConnection(conn,mapping);
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}finally{
			if(conn!=null){
				try {
					conn.commit();
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private void doInConnection(Connection conn,Document mapping) throws SQLException {
		Node tableNode=mapping.selectSingleNode("/hibernate-mapping/class/@table");
		if(tableNode==null)return;
		String table =tableNode.getText();
		Node idColumnNode=mapping.selectSingleNode("/hibernate-mapping/class/id/column/@name");
		if(idColumnNode==null)return;
		String idColumn=idColumnNode.getText();
		Node sequenceNode=mapping.selectSingleNode("/hibernate-mapping/class/id/generator/param");
		if(sequenceNode==null)return;
		String sequence=sequenceNode.getText();
		
		long start=1;
		StringBuffer maxIdSql=new StringBuffer().append("select max(").append(idColumn).append(") from ").append(table);
		Statement stmt=conn.createStatement();
		System.out.println("find sql:"+maxIdSql);
		ResultSet rs=stmt.executeQuery(maxIdSql.toString());
		while(rs.next()){
			System.out.println("max:"+rs.getLong(1));
			start=rs.getLong(1)+1;
		}
		StringBuffer dropSql=new StringBuffer();
		dropSql.append("DROP SEQUENCE ").append(sequence);
		StringBuffer createSql=new StringBuffer();
		createSql.append("CREATE SEQUENCE ").append(sequence).append(" START WITH ").append(start);
		System.out.println("drop sql:"+dropSql);
		System.out.println("create sql:"+createSql);
		stmt.addBatch(dropSql.toString());
		stmt.addBatch(createSql.toString());
		stmt.executeBatch();
		stmt.close();
	}
	
	public Document readHibernateXML(File xmlFile) throws DocumentException, IOException{
		SAXReader reader = new SAXReader();
		reader.setValidation(false);
		//reader.setEntityResolver(null);
		//reader.setIncludeExternalDTDDeclarations(false);
		reader.setStripWhitespaceText(false);
		reader.setMergeAdjacentText(false);
		reader.setEntityResolver(new HibernateDTDEntityResolver());
		reader.setErrorHandler( new ErrorHandler(){

			public void error(SAXParseException e) throws SAXException {
				e.printStackTrace();					
			}

			public void fatalError(SAXParseException e) throws SAXException {
				e.printStackTrace();
			}

			public void warning(SAXParseException e) throws SAXException {
				e.printStackTrace();
			}
				
		} );
		FileInputStream fis=new FileInputStream(xmlFile);
		Document doc=reader.read(fis);
		fis.close();
		return doc;
	}
	
	public Document readNoDTDXML(InputStream xmlInputStream) throws DocumentException, IOException{
		SAXReader reader = new SAXReader();
		reader.setValidation(false);
		//reader.setEntityResolver(null);
		//reader.setIncludeExternalDTDDeclarations(false);
		reader.setStripWhitespaceText(false);
		reader.setMergeAdjacentText(false);
		reader.setEntityResolver(new EntityResolver(){
			public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {				
				return null;
			}
		});
		reader.setErrorHandler( new ErrorHandler(){

			public void error(SAXParseException e) throws SAXException {
				e.printStackTrace();					
			}

			public void fatalError(SAXParseException e) throws SAXException {
				e.printStackTrace();
			}

			public void warning(SAXParseException e) throws SAXException {
				e.printStackTrace();
			}
				
		} );
		Document doc=reader.read(xmlInputStream);
		xmlInputStream.close();
		return doc;
	}
}
